package org.deltaset.meta.faces;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.deltaset.meta.MetaActionHandler;
import org.deltaset.meta.MetaEntry;
import org.deltaset.meta.extension.MetaHandlerProvider;
import org.deltaset.meta.extension.ProviderDecorator;

/**
 *
 * @author dmakariev
 */
public class CachingMetaHandlerProvider implements MetaHandlerProvider, ProviderDecorator<MetaHandlerProvider> {

    private MetaHandlerProvider defaultProvider;
    private static final Logger logger = Logger.getLogger(CachingMetaHandlerProvider.class.getName());

//    @Override
//    public MetaHandler createMetaHandler(Class entityClass) {
//        final long start = System.currentTimeMillis();
//
//        final StaticCache cache = StaticCache.INSTANCE;
//        if (!cache.contains(entityClass)) {
//            final MetaHandler metaHandler = getDefaultProvider().createMetaHandler(entityClass);
//            cache.put(entityClass, metaHandler);
//        }
//        final MetaHandler metaHandler = cache.get(entityClass);
//        final long createdTime = System.currentTimeMillis() - start;      
//        logger.log(Level.INFO, "~~~~~ !!!!!! created time={0}ms MetaHandler(entityClass={1})", new Object[]{createdTime, entityClass.getName()});
//        return metaHandler;
//    }
    @Override
    public void setDefaultProvider(final MetaHandlerProvider defaultProvider) {
        this.defaultProvider = defaultProvider;
    }

    @Override
    public MetaHandlerProvider getDefaultProvider() {
        return this.defaultProvider;
    }

    @Override
    public MetaActionHandler createMetaActionHandler() {
        return getDefaultProvider().createMetaActionHandler();
    }

    @Override
    public MetaEntry createMetaEntry(Class entityClass) {
        final long start = System.currentTimeMillis();

        final StaticCache cache = StaticCache.INSTANCE;
        if (!cache.containsMetaEntry(entityClass)) {
            final MetaEntry metaEntry = getDefaultProvider().createMetaEntry(entityClass);
            cache.putMetaEntry(entityClass, metaEntry);
        }
        final MetaEntry metaEntry = cache.getMetaEntry(entityClass);
        final long createdTime = System.currentTimeMillis() - start;
        logger.log(Level.INFO, "~~~~~ !!!!!! created time={0}ms createMetaEntry(entityClass={1})", new Object[]{createdTime, entityClass.getName()});
        return metaEntry;
    }

    private enum StaticCache {

        INSTANCE;
        private final Map<Class, MetaEntry> map;

        private StaticCache() {
            map = new ConcurrentHashMap<Class, MetaEntry>();
        }

        void putMetaEntry(final Class entityClass, final MetaEntry metaEntry) {
            map.put(entityClass, metaEntry);
        }

        MetaEntry getMetaEntry(final Class entityClass) {
            return map.get(entityClass);
        }

        boolean containsMetaEntry(final Class entityClass) {
            return map.containsKey(entityClass);
        }
    }
}
